package com.bblocks.http.converter;

import com.bblocks.util.KryoRedisSerializer;
import com.bblocks.util.KryoSerializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.GenericHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.lang.Nullable;

import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.charset.Charset;

/**
 * http的kryo编码（Accept: application/x-kryo-serialization）
 * 暂时只有响应编码(不支持读取)
 * 1、响应前不能设置响应相关参数，否则本地无效
 */
@Slf4j
public class KryoHttpMessageConverter extends AbstractHttpMessageConverter<Object> implements GenericHttpMessageConverter<Object> {

	public static final MediaType MEDIA_TYPE = new MediaType("application", "x-kryo-serialization", Charset.forName("UTF-8"));

	public KryoHttpMessageConverter() {
		// 构造方法中指明consumes（req）和produces（resp）的类型，指明这个类型才会使用这个converter
		super(MEDIA_TYPE);
	}
	@Override
	protected boolean supports(Class<?> clazz) {
		// 使用Serializable，这里可以直接返回true
		// 使用object，这里还要加上Serializable接口实现类判断
		// 根据自己的业务需求加上其他判断
		return true;
	}


	public boolean canRead(Class<?> clazz, @Nullable MediaType mediaType) {
		return supports(clazz) && canRead(mediaType);
	}
	public boolean canRead(Type type, Class<?> contextClass, MediaType mediaType) {
		return super.canRead(contextClass, mediaType);
	}

	@Override
	public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
		return readInternal(contextClass,inputMessage);
	}


	public boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType) {
		return false;
	}

	public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
		if(mediaType != null && MEDIA_TYPE.getSubtype().equalsIgnoreCase(mediaType.getSubtype())){
			return true;
		}
		return super.canWrite(clazz, mediaType);
	}

	@Override
	public void write(Object o, Type type, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
		writeInternal(o,outputMessage);
	}

	/**
	 * 读取暂时不用
	 * @param clazz
	 * @param inputMessage
	 * @return
	 * @throws IOException
	 * @throws HttpMessageNotReadableException
	 */
	@Override
	protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage)
			throws IOException, HttpMessageNotReadableException {
		try {
			return KryoSerializer.getInstance().deserialize(inputMessage.getBody());
		} catch (IOException ioe) {
			throw ioe;
		} catch (Exception e) {
			log.error("exception when java deserialize:", e);
			throw new HttpMessageNotReadableException("解码失败");
		}
	}
	@Override
	protected void writeInternal(Object object, HttpOutputMessage outputMessage)
			throws IOException, HttpMessageNotWritableException {
		KryoRedisSerializer<Object> kryo = new KryoRedisSerializer<>(Object.class);
		try {
			outputMessage.getHeaders().setContentType(MEDIA_TYPE);
			KryoSerializer.getInstance().serialize(object,outputMessage.getBody());
		} catch (IOException ioe) {
			throw ioe;
		}catch (Exception e){
			log.error("exception when kryo deserialize：",e);
			throw new HttpMessageNotWritableException("编码失败");
		}

	}
}